spec:
  type: rego
  data: |-
    import future.keywords.contains
    import future.keywords.if
    
    violation contains {"msg": msg} if {
      params := object.get(input, "parameters", {})
      objName := input.review.name
    
      affectedServiceAccounts := object.get(params, "affectedServiceAccounts", [])
      affected(input.review.userInfo.username, affectedServiceAccounts)
    
      allowSA := object.get(params, "serviceAccounts", [])
      checkAllSARoles(input.review.object.subjects, allowSA, input.review.object.roleRef)
      msg := sprintf("Create binding '%v' denied. Role disallowed.", [objName])
    }
    
    violation contains {"msg": msg} if {
      params := object.get(input, "parameters", {})
      objName := input.review.name
    
      affectedServiceAccounts := object.get(params, "affectedServiceAccounts", [])
      affected(input.review.userInfo.username, affectedServiceAccounts)
    
      allowSA := object.get(params, "serviceAccounts", [])
      checkAllSA(input.review.object.subjects, allowSA)
      msg := sprintf("Create binding '%v' denied. SA disallowed.", [objName])
    }
    
    violation contains {"msg": msg} if {
      input.review.kind.kind = "ClusterRoleBinding"
      params := object.get(input, "parameters", {})
      objName := input.review.name
    
      affectedServiceAccounts := object.get(params, "affectedServiceAccounts", [])
      affected(input.review.userInfo.username, affectedServiceAccounts)
    
      allowNamespaces := object.get(params, "allowedNamespaces", [])
      checkAllNamespaces(input.review.object.subjects, allowNamespaces)
    
      msg := sprintf("Create binding '%v' denied. Namespace disallowed.", [objName])
    }
    
    violation contains {"msg": msg} if {
      input.review.kind.kind = "RoleBinding"
      params := object.get(input, "parameters", {})
      objName := input.review.name
    
      affectedServiceAccounts := object.get(params, "affectedServiceAccounts", [])
      affected(input.review.userInfo.username, affectedServiceAccounts)
    
      allowNamespaces := object.get(params, "allowedNamespaces", [])
      not checkSimpleMatchAny(input.review.object.metadata.namespace, allowNamespaces)
    
      msg := sprintf("Create binding '%v' denied. Namespace disallowed.", [objName])
    }
    
    checkAllNamespaces(subjects, namespaces) if {
      subject := subjects[_]
        not checkSimpleMatchAny(subject.namespace, namespaces)
    }
    
    checkMatchAny(objName, roles) if {
      role := roles[_]
      roleName := object.get(role, "pattern", "")
      regex.match(roleName, objName)
    }
    
    checkSimpleMatchAny(objName, roles) if {
      role := roles[_]
      regex.match(role, objName)
    }
    
    checkAllSARoles(subjects, allowed, roleref) if {
      sa := subjects[_]
      not checkSAMatchRole(sa.name, allowed, roleref)
    }
    
    checkSAMatchRole(saName, allowed, roleref) if {
      sa := allowed[_]
      saNamePattern := object.get(sa, "name", "")
      regex.match(saNamePattern, saName)
      saAllowedRoles := object.get(sa, "roles", "")
      checkSimpleMatchAny(roleref.name, saAllowedRoles)
    }
    
    checkAllSA(subjects, allowed) if {
      sa := subjects[_]
      not checkSAMatchAny(sa.name, allowed)
    }
    
    checkSAMatchAny(saName, allowed) if {
      sa := allowed[_]
      saNamePattern := object.get(sa, "name", "")
      regex.match(saNamePattern, saName)
    }
    
    affected(userInfo, affectedServiceAccounts) if {
      username := affectedServiceAccounts[_]
      regex.match(username, userInfo)
    }